﻿using Pivotbrowser.Web;
using System;
using System.Net;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Pivotbrowser.Helpers;
using System.ServiceModel.DomainServices.Client;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;

namespace Pivotbrowser.Models
{


    public class PrüfungStudent
    {
        public string ZEUGNISBEZ { get; set; }
        public string SEMESTERNR { get; set; }
        public string SEMESTERBEZ { get; set; }
        public string STUDFACH { get; set; }
        public string NOTE_ { get; set; }
        public string TITEL { get; set; }
        public double ECTS { get; set; }
        public string PRFBEMNR { get; set; }
        public string BESTANDEN { get; set; }
        public string FACHSEM { get; set; }
    }
    public class MinimalStudent
    {
        // Persona
        public string MATRNR { get; set; }
        public string VORNAME { get; set; }
        public string NACHNAME { get; set; }
        public int ALTER { get { int age = DateTime.Today.Year - this.GEBDATUM.Year; if (DateTime.Today < this.GEBDATUM.AddYears(age)) age--; return age; } }
        public DateTime GEBDATUM { get; set; }
        public string TELEFONNR { get; set; }
        public string MAIL { get; set; }
        public string MAIL2 { get; set; }
        public string PLZ { get; set; }
        public string SEX { get; set; }
        public SolidColorBrush SexColor { get; set; }
        public string ORT { get; set; }
        public string STRASSE { get; set; }
        public string NOTIZEN { get; set; }
        public string NOTIZ { get; set; }
        public string MARKER { get; set; }

        // Fach & Semester
        public string STUDFACH { get; set; }
        public string AKTIV { get; set; }
        public int FACHSEMESTER { get; set; }
        public string JUNIORSTUDIUM { get; set; }
        public int HOCHSCHULSEMESTER { get; set; }
        
        // Prüfungen
        public List<PrüfungStudent> AltePrüfungen { get; set; }
        public List<PrüfungStudent> p_collection_all { get; set; }
        private List<PrüfungStudent> _p_collection;
        public List<PrüfungStudent> p_collection 
        {
            get { return _p_collection; }
            set
            {
                _p_collection = value;
                p_collection_all = new List<PrüfungStudent>(value);
                this.RELEVANTSEMESTER = new ComparableStringList();
                this.PRÜFUNGSFÄCHER = new ComparableStringList();
                this.PRÜFUNGSNOTEN = new ComparableStringList();
                this.PRÜFFACHSEM = new ComparableStringList();

                foreach (PrüfungStudent ps in _p_collection)
                {
                    if (!this.RELEVANTSEMESTER.Contains(ps.SEMESTERNR + ": " + ps.SEMESTERBEZ))
                    {
                        this.RELEVANTSEMESTER.Add(ps.SEMESTERNR + ": " + ps.SEMESTERBEZ);
                    }

                    if (!this.PRÜFFACHSEM.Contains(ps.FACHSEM))
                    {
                        this.PRÜFFACHSEM.Add(ps.FACHSEM);
                    }

                    if (!this.PRÜFUNGSFÄCHER.Contains(ps.ZEUGNISBEZ))
                    {
                        this.PRÜFUNGSFÄCHER.Add(ps.ZEUGNISBEZ);
                    }

                    if (!this.PRÜFUNGSNOTEN.Contains(ps.NOTE_))
                    {
                        this.PRÜFUNGSNOTEN.Add(ps.NOTE_);
                    }
                }
            }
        }

        public double NOTENDURCHSCHNITT { get; set; }
        public double ECTSGESAMT { get; set; }

        public ComparableStringList RELEVANTSEMESTER { get; set; }
        public ComparableStringList PRÜFUNGSFÄCHER { get; set; }
        public ComparableStringList PRÜFUNGSNOTEN { get; set; }
        public ComparableStringList PRÜFFACHSEM { get; set; }


        // Misc
        public SolidColorBrush MarkerColor { get; set; }

        public void FilterCollectionByRelevantSemesters(List<string> rs_list)
        {
            if (rs_list.Count > 0)
            {
                List<PrüfungStudent> temp = new List<PrüfungStudent>();

                foreach (var ps in p_collection)
                {
                    bool keep = false;
                    foreach (var rs in rs_list)
                    {
                        if (ps.SEMESTERNR + ": " + ps.SEMESTERBEZ == rs)
                        {
                            keep = true;
                            break;
                        }
                    }
                    if (!keep && p_collection.Contains(ps))
                    {
                        temp.Add(ps);
                    }
                }

                foreach (var ps in temp)
                    p_collection.Remove(ps);
            }
        }

        public void FilterCollectionByFachSemesters(List<string> fs_list)
        {
            if (fs_list.Count > 0)
            {
                List<PrüfungStudent> temp = new List<PrüfungStudent>();

                foreach (var ps in p_collection)
                {
                    bool keep = false;
                    foreach (var fs in fs_list)
                    {
                        if (ps.FACHSEM == fs)
                        {
                            keep = true;
                            break;
                        }
                    }
                    if (!keep && p_collection.Contains(ps))
                    {
                        temp.Add(ps);
                    }
                }
            
            foreach ( var ps in temp)
                p_collection.Remove(ps);
        }
        }

        public void FilterCollectionByPruefFach(List<string> pf_list)
        {
            if (pf_list.Count > 0)
            {
                List<PrüfungStudent> temp = new List<PrüfungStudent>();

                foreach (var ps in p_collection)
                {
                    bool keep = false;
                    foreach (var pf in pf_list)
                    {
                        if (ps.ZEUGNISBEZ == pf)
                        {
                            keep = true;
                            break;
                        }
                    }
                    if (!keep && p_collection.Contains(ps))
                    {
                        temp.Add(ps);
                    }
                }
            
            foreach (var ps in temp)
                p_collection.Remove(ps);
            }
        }

        public void FilterCollectionByNote(List<string> no_list)
        {
            if (no_list.Count > 0)
            {
                List<PrüfungStudent> temp = new List<PrüfungStudent>();

                foreach (var ps in p_collection)
                {
                    bool keep = false;
                    foreach (var no in no_list)
                    {
                        if (ps.NOTE_ == no)
                        {
                            keep = true;
                            break;
                        }
                    }
                    if (!keep && p_collection.Contains(ps))
                    {
                        temp.Add(ps);
                    }
                }
                foreach (var ps in temp)
                   p_collection.Remove(ps);
            }
        }

        public void ResetCollection()
        {
            p_collection.Clear();
            foreach (var pf in p_collection_all)
            {
                p_collection.Add(pf);
            }
        }

        public void ResetLists()
        {
            foreach (var ps in p_collection_all)
            {
                if (!this.RELEVANTSEMESTER.Contains(ps.SEMESTERNR + ": " + ps.SEMESTERBEZ))
                {
                    this.RELEVANTSEMESTER.Add(ps.SEMESTERNR + ": " + ps.SEMESTERBEZ);
                }

                if (!this.PRÜFFACHSEM.Contains(ps.FACHSEM))
                {
                    this.PRÜFFACHSEM.Add(ps.FACHSEM);
                }

                if (!this.PRÜFUNGSFÄCHER.Contains(ps.ZEUGNISBEZ))
                {
                    this.PRÜFUNGSFÄCHER.Add(ps.ZEUGNISBEZ);
                }

                if (!this.PRÜFUNGSNOTEN.Contains(ps.NOTE_))
                {
                    this.PRÜFUNGSNOTEN.Add(ps.NOTE_);
                }
            }
        }


        public void UpdateListRelevantSemester()
        {
            RELEVANTSEMESTER.Clear();
            foreach (var ps in p_collection)
            {
                if (!RELEVANTSEMESTER.Contains(ps.SEMESTERNR + ": " + ps.SEMESTERBEZ))
                    RELEVANTSEMESTER.Add(ps.SEMESTERNR + ": " + ps.SEMESTERBEZ);
            }
        }


        public void UpdateListPruefFach()
        {
            PRÜFUNGSFÄCHER.Clear();
            foreach (var ps in p_collection)
            {
                if (!PRÜFUNGSFÄCHER.Contains(ps.ZEUGNISBEZ))
                    PRÜFUNGSFÄCHER.Add(ps.ZEUGNISBEZ);
            }
        }

        public void UpdateListFachSem()
        {
            PRÜFFACHSEM.Clear();
            foreach (var ps in p_collection)
            {
                if (!PRÜFFACHSEM.Contains(ps.FACHSEM))
                    PRÜFFACHSEM.Add(ps.FACHSEM);
            }
        }


        public void UpdateListNote()
        {
            PRÜFUNGSNOTEN.Clear();
            foreach (var ps in p_collection)
            {
                if (!PRÜFUNGSNOTEN.Contains(ps.NOTE_))
                    PRÜFUNGSNOTEN.Add(ps.NOTE_);
            }
        }
   }


    public static class Factory
    {
        public static MinimalStudent BuildMinimalStudent(Student s, List<Semester> currentsemesters)
        {
            // try build Student
            try
            {
            // only Bachelor Winfo and Master Winfo Students allowed

            StudentenFachSemester sfs = null;
            if ( s.STUDENTENFACHSEMESTER.Count > 0 )
                sfs = s.STUDENTENFACHSEMESTER.OrderByDescending(x => Int32.Parse(x.SEMESTERNR)).First();

            string studfach = sfs == null ? "K.A." : sfs.STUDFACH;

            if (studfach != "MWInf" && studfach != "WINF")
                return null;
    
                var nms = new MinimalStudent()
                {
                    MATRNR = s.MATRNR,
                    VORNAME = s.VORNAME,
                    NACHNAME = s.NACHNAME,
                    GEBDATUM = DateTime.ParseExact(s.GDATUM, "yyyy'-'MM'-'dd", CultureInfo.CurrentCulture, DateTimeStyles.None),
                    SEX = s.SEX == "0" ? "weiblich" : "männlich",
                    SexColor = s.MATRNR == "2534080" || s.MATRNR == "2525566" ? new SolidColorBrush(Colors.Black) : ( s.SEX == "0" ? new SolidColorBrush(Color.FromArgb(255, 255, 105, 180)) : new SolidColorBrush(Color.FromArgb(255, 30, 144, 255)) ),
                    ORT = s.ORT1,
                    STRASSE = s.STRASSE1,
                    PLZ = s.PLZ1,
                    TELEFONNR = s.TELEFON1,
                    MAIL = s.EMAIL,
                    MAIL2 = s.EMAIL2,
                    NOTIZEN = s.NOTIZEN != null && s.NOTIZEN.NOTIZ != null && s.NOTIZEN.NOTIZ.Trim() != "" ? "hat Notizen" : "hat keine Notiz",
                    NOTIZ = s.NOTIZEN != null ? s.NOTIZEN.NOTIZ : "",
                    HOCHSCHULSEMESTER = s.STUDENTENFACHSEMESTER.Where(x => Int32.Parse(x.SEMESTERNR) > 0).Count(),
                    STUDFACH = studfach == "WINF" ? "Bachelor Winfo" : "Master Winfo",
                    AKTIV = sfs.SEMESTERNR == currentsemesters[0].SEMESTERNR || sfs.SEMESTERNR == currentsemesters[1].SEMESTERNR ? "Ja" : sfs.SEMESTERNR == currentsemesters[2].SEMESTERNR ? "Ausstehend" : "Nein (Letztes: " + sfs.SEMESTER.BEZ + ")", // USE A PARAMETERS TABLE
                    FACHSEMESTER = sfs.FACHSEM == "(null)" ?  0 : Int32.Parse(sfs.FACHSEM),
                    JUNIORSTUDIUM = sfs.FACHSEM == "(null)" ? "ist Juniorstudent" : s.STUDENTENFACHSEMESTER.Where(x => x.FACHSEM == "(null)" && Int32.Parse(x.SEMESTERNR) > 0).Count() > 0 ? "war Juniorstudent" : "war nie Juniorstudent",
                    MarkerColor = MapColor(s.NOTIZEN != null ? s.NOTIZEN.MARKER : ""),
                    MARKER = s.NOTIZEN != null ? s.NOTIZEN.MARKER : "Keine Markierung"
                };

                UpdatePrüfungen(nms, s, studfach);
                CalculateAverage(nms);
                return nms;
            }
            catch (Exception exc)
            {
                var newstud = new MinimalStudent()
                {
                    MATRNR = s.MATRNR,
                    NACHNAME = "Error",
                    VORNAME = "On Import",
                    NOTIZ = exc.Message
                };
                return newstud;
            }
        }

        public static PrüfungStudent BuildPrüfungStudent(Student s, Prüfung_Student p)
        {
            var ps = new PrüfungStudent()
            {
                ZEUGNISBEZ = p.TEILPRÜFUNG == null ? "K.A." : p.TEILPRÜFUNG.ZEUGNISBEZ,
                SEMESTERNR = p.SEMESTERNR,
                SEMESTERBEZ = p.SEMESTER.BEZ,
                NOTE_ = p.NOTE_,
                STUDFACH = p.STUDFACH == "WINF" ? "Bachelor Winfo" : p.STUDFACH == "MWInf" ? "Master Winfo" : p.STUDFACH,
                TITEL = p.TITEL,
                PRFBEMNR = p.PRFBEM,
                BESTANDEN = p.PRÜFUNGSBEMERKUNG.BESTANDEN,
                FACHSEM = s.STUDENTENFACHSEMESTER.Where(x => x.SEMESTERNR == p.SEMESTERNR).Count() > 0 ? s.STUDENTENFACHSEMESTER.Where(x => x.SEMESTERNR == p.SEMESTERNR).First().FACHSEM.StartsWith("(nu") ? "J" : s.STUDENTENFACHSEMESTER.Where(x => x.SEMESTERNR == p.SEMESTERNR).First().FACHSEM : "0"
            };

            if (ps.ZEUGNISBEZ == "Seminar")
            {
                var str = p.PRÜFUNGSFACH == null ? "K.A." : p.PRÜFUNGSFACH.BEZ;
                ps.ZEUGNISBEZ = "Seminar in " + str;
            }


            if ((p.NOTE_ == "(null)" || p.NOTE_ == "5.0") && p.PRÜFUNGSBEMERKUNG != null)
            {
                ps.NOTE_ = p.PRÜFUNGSBEMERKUNG.BEZ == "<Ohne>" ? "Ohne Bemerkung (nicht bestanden)" : p.PRÜFUNGSBEMERKUNG.BEZ;
            }

            try
            {
                if (p.TEILPRÜFUNG.ECTS == "(null)")
                {
                    ps.ECTS = Double.Parse(p.PRÜFUNGSFACHVERSION.ECTS, new CultureInfo("en-US"));
                }
                else
                {
                    ps.ECTS = Double.Parse(p.TEILPRÜFUNG.ECTS, new CultureInfo("en-US"));
                }
            }
            catch
            {
                ps.ECTS = 0.0;
            }

            if (p.TITEL == "(null)" || p.TITEL.Trim() == "")
            {
                ps.TITEL = null;
            }

            return ps;
        }

        private static List<PrüfungStudent> RemoveMultipleTries( List<PrüfungStudent> entities )
        {
            var list = entities.OrderByDescending(x => x.BESTANDEN).OrderBy(x => x.NOTE_).ToList();
            Dictionary<string, PrüfungStudent> dict = new Dictionary<string, PrüfungStudent>();

            foreach (PrüfungStudent ps in list)
            {
                if (dict.ContainsKey(ps.ZEUGNISBEZ))
                    continue;
                else
                    dict.Add(ps.ZEUGNISBEZ, ps);
            }

            return dict.Values.ToList();
        }

        private static void CalculateAverage(MinimalStudent ms)
        {
            var cut = RemoveMultipleTries(ms.p_collection_all);

            double sum = 0;
            double div = 0;
            double ects_sum = 0;

            CultureInfo ci = new CultureInfo("en-US");

                foreach (var ps in cut)
                {                      
                        double ects;
                        double note;
                        try
                        {
                            ects = ps.ECTS;
                            note = Double.Parse(ps.NOTE_, ci);

                            if (note >= 5.0)
                            {
                                continue;
                            }
                        }
                        catch
                        {
                            if (ps.PRFBEMNR == "7" || ps.PRFBEMNR == "11" || ps.PRFBEMNR == "13")
                            {
                                try { ects_sum += ps.ECTS; }
                                catch { }
                            }
                            continue;
                        }

                        sum += (ects * note);
                        div += ects;
                        ects_sum += ects;
                    }

                if (div == 0)
                {
                    ms.NOTENDURCHSCHNITT = 0;
                    return;
                }

                ms.ECTSGESAMT = ects_sum;
                ms.NOTENDURCHSCHNITT = Math.Round(sum / div, 2);
        }

        private static void UpdatePrüfungen(MinimalStudent mns, Student s, string studfach)
        {
            EntityCollection<Prüfung_Student> entities = s.PRÜFUNG_STUDENT;
            List<PrüfungStudent> history = new List<PrüfungStudent>();
            List<PrüfungStudent> current = new List<PrüfungStudent>();
            foreach (Prüfung_Student ps in entities)
            {
                if (Int32.Parse(ps.SEMESTERNR) > 0)
                {
                    if (ps.STUDFACH == studfach)
                        current.Add(BuildPrüfungStudent(s, ps));
                    else
                        history.Add(BuildPrüfungStudent(s, ps));
                }
            }

            mns.p_collection = current;
            mns.AltePrüfungen = history;
        }

        private static SolidColorBrush MapColor(string s) 
        {
            if (s == "Grün")
                return new SolidColorBrush(Colors.Green);

            if (s == "Gelb")
                return new SolidColorBrush(Colors.Yellow);

            if (s == "Lila")
                return new SolidColorBrush(Colors.Purple);

            if (s == "Rot")
                return new SolidColorBrush(Colors.Red);

            if (s == "Orange")
                return new SolidColorBrush(Colors.Orange);


            return new SolidColorBrush(Colors.Transparent);
        }
    }
}
